<?php

namespace CMS;

abstract class Ctrl {
	private $standalone = false;

	protected $email;
	protected $request;
	protected $session;
	protected $cookie;

	protected $db;
	protected $uri;
	protected $noty;
	protected $view;
	protected $settings;
	protected $layout = 'frontend';

	public function __construct($uri = false, $noty = false) {
		// standalone controller?
		$this->standalone = $uri === 'standalone' ? true : false;

		// load classes
		$this->email = new Email();
		$this->request = new Request();
		$this->session = new Persist('session');
		$this->cookie = new Persist('cookie');

		// load vars
		$this->db = Db::$db;
		$this->uri = is_array($uri) ? $uri : array();
		$this->noty = is_array($noty) ? $noty : array();

		// get settings
		$this->_getSettings();

		// the all important view var (and set default title)
		$this->view = new \stdClass;
		$this->view->title = $this->settings['blizz_guild'] . ' - ' . $this->_getName();

		// autologin & set auth & guest
		if(!$this->standalone) {
			$this->_autologin();
			$this->_setAuth();
			$this->_setGuest();
		}

		// run
		$this->run();
	}

	// get settings
	private function _getSettings() {
		// the query
		$result = $this->db->query("SELECT key, value FROM settings");

		// populate the variable
		$this->settings = array();
		while($res = $result->fetchArray(SQLITE3_ASSOC))
			$this->settings[$res['key']] = (string)$res['value'];
	}

	// autologin if we have a cookie
	private function _autologin() {
		// no remember me? stop here
		if(!isset($this->cookie->auth))
			return false;

		// already logged in? stop here
		if(isset($this->session->auth))
			return false;

		// decode cookie
		$info = base64_decode($this->cookie->auth);
		$id = $this->db->escapeString((int)substr($info, 32));
		$password = $this->db->escapeString((string)substr($info, 0, 32));

		// find in db
		$result = $this->db->querySingle("SELECT id FROM users WHERE id = '{$id}' AND password = '{$password}'", true);
		if(!$result)
			return false;

		// set name to autologin view to broadcast our presence
		$this->view->autologin = true;

		// set as logged in
		$this->session->auth = $result;
	}

	// set permissions
	private function _setAuth() {
		// not logged in? stop here
		if(!isset($this->session->auth))
			return false;

		// get permission
		$result = $this->db->querySingle("SELECT
			u.*, r.name as rank_name, r.permissions

			FROM users AS u
			LEFT JOIN ranks AS r ON u.rank = r.id

			WHERE u.id = '{$this->session->auth['id']}'", true);

		// user not found? unset auth
		if(!$result) {
			unset($this->session->auth);
			return false;
		}

		// set avatar and link
		$result['avatar'] = md5(strtolower($result['email']));
		$result['link'] = $result['id'] . '-' . Helper::generate_named_id($result['name']);

		// unserialize permissions
		$result['permissions'] = unserialize($result['permissions']);

		// set session
		$this->session->auth = $result;
	}

	// set guest permissions
	private function _setGuest() {
		// is logged in? stop here
		if(isset($this->session->auth)) {
			unset($this->session->guest);
			return false;
		}

		// get the 'public' forum view permissions
		$result = $this->db->query("SELECT id FROM categories WHERE type != 0");

		// transform
		$data = array();
		while($res = $result->fetchArray(SQLITE3_ASSOC))
			$data[$res['id']] = (string)$res['id'];

		// set 'public' forum view permissions in the guest session
		$this->session->guest = array(
			'permissions' => array(
				'forum' => array(
					'view' => $data
				)
			)
		);
	}

	// get class name
	protected function _getName() {
		$name = explode('\\', get_class($this));
		return end($name);
	}

	// load a view from another view (or helper)
	public function partial($file, $variables = array()) {
		// make variables global (sorta)
		foreach($variables as $idx => $value)
			$$idx = $value;

		// get output from layout
		ob_start();
		include(ROOT . DS . 'app' . DS . 'view' . DS . $file);
		return ob_get_clean();
	}

	// on ctrl echo
	public function __toString() {
		// to catch a predator
		try {
			// not standalone? set css and js
			if(!$this->standalone) {
				$srcm = new Min();
				$this->view->static_css = $srcm->static_css;
				$this->view->static_js = $srcm->static_js;
			}

		// this predator is google closure compiler :=)
		} catch (\Exception $e) {
			// dump($e);
			die('Error minifying css or js files. Please report this to the person in charge');
		}

		// set location
		$this->view->location = array(
			'title' => $this->view->title,
			'ctrl' => strtolower($this->_getName()),
			'path' => isset($this->view->path) ? $this->view->path : array()
		);

		// get output from view
		ob_start();
		include(ROOT . DS . 'app' . DS . 'view' . DS . $this->view->location['ctrl'] . '.php');
		$this->output = ob_get_clean();

		// callback for simulated jsonp
		if(!is_null($this->request->post('callback'))) {
			header('Content-type: application/json');
			return json_encode(array(
				'success' => true,
				'noty' => $this->noty,
				'location' => $this->view->location,
				'html' => \Minify_HTML::minify($this->output)
			));
		}

		// get output from layout
		ob_start();
		include(ROOT . DS . 'app' . DS . 'layout' . DS . strtolower($this->layout) . '.php');
		return ENV == 1 ? \Minify_HTML::minify(ob_get_clean()) : ob_get_clean();
	}

	// no method for controller? go to error
	public function __call($func, $arg) {
		die(new \APP\Ctrl\Error($this->uri));
	}
}